home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d3 / tedplus.arc / TED.ASM < prev    next >
Assembly Source File  |  1988-11-29  |  50KB  |  1,695 lines

  1. ;======================================================================
  2. ;  TED.ASM -- The Tiny EDitor.
  3. ;  PC Magazine * Tom Kihlken * tktktk
  4. ;----------------------------------------------------------------------
  5. CSEG        SEGMENT
  6.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  7.         ORG    100H        ;Beginning for .COM programs
  8. START:
  9.         JMP    BEGIN
  10.  
  11. ;-----------------------------------------------------------------------
  12. ; Local data area
  13. ;-----------------------------------------------------------------------
  14. TAB        EQU    9
  15. CR        EQU    13
  16. LF        EQU    10
  17. LFCR        EQU    0A0DH
  18.  
  19. COPYRIGHT    DB    CR,LF,"TED 1.0 (c) 1988 Ziff Communications Co."
  20.         DB    CR,LF,"PC Magazine ",254," Tom Kihlken$",1AH
  21.  
  22. FILE_TOO_BIG    DB    "File too big$"
  23. READ_ERR_MESS    DB    "Read error$"
  24. MEMORY_ERROR    DB    "Not enough memory$"
  25.  
  26. PROMPT_STRING    DB    "1ABORT",0,"2UNDO",0,"3PRINT",0
  27.         DB    "4MARK",0,"5CUT",0,"6PASTE",0,"7EXIT",0
  28.         DB    "8DEL EOL",0,"9FIND",0,"10UDEL L",0,0
  29. PROMPT_LENGTH    =    $ - OFFSET PROMPT_STRING
  30.  
  31. SAVE_MESS    DB    "Save as: ",0
  32. DOT_$$$        DB    ".$$$",0
  33. DOT_BAK        DB    ".BAK",0
  34. SRCH_PROMPT     DB      "SEARCH STRING> ",0
  35. SRCH_MAX    DB    66
  36. SRCH_SIZ    DB    0
  37. SRCH_STR        DB      66 DUP (0)
  38. SRCH_FLG    DB    0
  39. SRCH_END    DW    0
  40. SRCH_BASE    DW    0
  41. SRCH_CLR    DB    244
  42. KP_CR        DB    0
  43. DIRTY_BITS    DB    1
  44. ORGATR      DB    0
  45. NORMAL        DB    91
  46. INVERSE        DB    33
  47. LEFT_MARGIN    DB    0
  48. MARGIN_COUNT    DB    0
  49. INSERT_MODE    DB    -1
  50. MARK_MODE    DB    0
  51. ROWS        DB    23
  52. SAVE_COLUMN    DB    0
  53. SAVE_ROW    DB    0
  54. LINE_FLAG    DB    0
  55. EVEN
  56. NAME_POINTER    DW    81H
  57. NAME_END    DW    81H
  58. STATUS_REG    DW    ?
  59. VIDEO_SEG    DW    0B000H
  60. LINE_LENGTH    DW    0
  61. UNDO_LENGTH    DW    0
  62. CUR_POSN    DW    0
  63. MARK_START    DW    0FFFFH
  64. MARK_END    DW    0
  65. MARK_HOME    DW    0
  66. TOP_OF_SCREEN    DW    0
  67. CURSOR        DW    0
  68. LAST_CHAR    DW    0
  69. COLUMNSB    LABEL    BYTE
  70. COLUMNS        DW    ?
  71. PASTE_SEG    DW    ?
  72. PASTE_SIZE    DW    0
  73. PAGE_PROC    DW    ?
  74. OLDINT24    DD    ?
  75. DISPATCH_TABLE    DW    OFFSET ABORT    ,OFFSET UNDO   ,OFFSET PRINT
  76.         DW    OFFSET MARK    ,OFFSET CUT    ,OFFSET PASTE
  77.         DW    OFFSET EXIT    ,OFFSET DEL_EOL,OFFSET FIND_STR
  78.         DW    OFFSET UDEL_L  ,OFFSET BAD_KEY,OFFSET BAD_KEY
  79.         DW    OFFSET HOME    ,OFFSET UP     ,OFFSET PGUP
  80.         DW    OFFSET BAD_KEY ,OFFSET LEFT   ,OFFSET BAD_KEY
  81.         DW    OFFSET RIGHT   ,OFFSET BAD_KEY,OFFSET ENDD
  82.         DW    OFFSET DOWN    ,OFFSET PGDN   ,OFFSET INSERT
  83.         DW    OFFSET DEL_CHAR
  84.  
  85. ; The following machine instruction removes the desnow delay.  It is
  86. ; inserted into the code for EGA, VGA, and MONO displays.
  87.  
  88. NO_DESNOW = 0EBH + (OFFSET WRITE_IT - OFFSET HWAIT - 2) * 256
  89.  
  90. ;-----------------------------------------------------------------------
  91. ; We start by initialize the display, then allocate memory for the file
  92. ; and paste segments.  Parse the command line for a filename, if one was
  93. ; input, read in the file.  Finally set the INT 23 and 24 vectors.
  94. ;-----------------------------------------------------------------------
  95. BEGIN:
  96.         XOR    AX,AX
  97.         MOV    DS,AX        ;Get a zero into DS
  98.         ASSUME    DS:NOTHING
  99.         MOV    AH,12H
  100.         MOV    BL,10H        ;Get EGA info
  101.         INT    10H
  102.         CMP    BL,10H        ;Did BL change?
  103.         JE    NOT_EGA        ;If not, no EGA in system
  104.         TEST    BYTE PTR DS:[0487H],8    ;Is EGA active?
  105.         JNZ    NOT_EGA
  106.         MOV    WORD PTR CS:HWAIT,NO_DESNOW ;Get rid of desnow
  107.         MOV    AX,DS:[0484H]    ;Get number of rows
  108.         DEC    AL        ;Last row is for prompt line
  109.          MOV    CS:[ROWS],AL    ;Save the number of rows
  110. NOT_EGA:
  111.         MOV    AX,DS:[044AH]    ;Get number of columns
  112.         MOV    CS:COLUMNS,AX    ;and store it
  113.         MOV    AX,DS:[0463H]    ;Address of display card
  114.         ADD    AX,6        ;Add six to get status port
  115.         PUSH    CS
  116.         POP    DS
  117.         ASSUME    DS:CSEG
  118.         MOV    STATUS_REG,AX
  119.         CMP    AX,3BAH        ;Is this a MONO display?
  120.         JNE    COLOR        ;If not, must be a CGA
  121.         MOV    WORD PTR HWAIT,NO_DESNOW ;Get rid of desnow
  122.         JMP    SHORT MOVE_STACK
  123. COLOR:
  124.         MOV    VIDEO_SEG,0B800H;Segment for color card
  125.         XOR    BH,BH        ;Use page zero
  126.         MOV    AH,8        ;Get current attribute
  127.         INT    10H
  128.         MOV    ORGATR,AH    ;Save the original attribute
  129. MOVE_STACK:
  130.         MOV    BX,OFFSET NEW_STACK
  131.         MOV    SP,BX        ;Move the stack downward
  132.         ADD    BX,15
  133.         MOV    CL,4        ;Convert program size to
  134.         SHR    BX,CL        ; paragraphs
  135.         MOV    AH,4AH        ;Deallocate unused memory
  136.         INT    21H
  137.         MOV    BX,1000H    ;Request 64K for file segment
  138.         MOV    AH,48H
  139.         INT    21H
  140.         MOV    ES,AX
  141.         ASSUME    ES:FILE_SEG
  142.         MOV    AH,48H
  143.         INT    21H        ;Request 64K for paste buffer
  144.         JNC    GOT_ENOUGH    ;If enough memory, continue
  145. NOT_ENOUGH:
  146.         MOV    DX,OFFSET MEMORY_ERROR
  147. ERR_EXIT:
  148.         PUSH    CS
  149.         POP    DS
  150.         MOV    AH,9        ;Write the error message
  151.         INT    21H        ;DOS display service
  152.         JMP    EXIT_TO_DOS    ;Exit this program
  153. GOT_ENOUGH:
  154.         MOV    PASTE_SEG,AX    ;Use this for the paste buffer
  155. GET_FILENAME:
  156.         MOV    SI,80H        ;Point to parameters
  157.         MOV    CL,[SI]        ;Get number of characters
  158.         XOR    CH,CH        ;Make it a word
  159.         INC    SI        ;Point to first character
  160.         PUSH    SI
  161.         ADD    SI,CX        ;Point to last character
  162.         MOV    BYTE PTR [SI],0    ;Make it an ASCII string
  163.         MOV    NAME_END,SI    ;Save pointer to last character
  164.         POP    SI        ;Get back pointer to filename
  165.         CLD
  166.         JCXZ    NO_FILENAME    ;If no params, just exit
  167. DEL_SPACES:    LODSB            ;Get character into AL
  168.         CMP    AL," "        ;Is it a space?
  169.         JNE    FOUND_LETTER
  170.         LOOP    DEL_SPACES
  171. FOUND_LETTER:
  172.         DEC    SI        ;Backup pointer to first letter
  173.         MOV    NAME_POINTER,SI    ;Save pointer to filename
  174.         MOV    DX,SI
  175.         MOV    AX,3D00H    ;Setup to open file
  176.         INT    21H
  177.         JC    NO_FILENAME     ;If we can't open, must be new file
  178. FILE_OPENED:
  179.         PUSH    ES
  180.         POP    DS        ;DS has file segment also
  181.         ASSUME    DS:FILE_SEG
  182.         MOV    BX,AX        ;Get the handle into BX
  183.         XOR    DX,DX        ;Point to file buffer
  184.         MOV    AH,3FH        ;Read service
  185.         MOV    CX,0FFFEH    ;Read almost 64K bytes
  186.         INT    21H
  187.         MOV    DI,AX        ;Number of bytes read in
  188.         JNC    NO_RD_ERR    ;If no error, take jump
  189.         MOV    DX,OFFSET READ_ERR_MESS
  190.         JMP    SHORT ERR_EXIT
  191. NO_RD_ERR:
  192.         MOV    LAST_CHAR,DI    ;Save the file size
  193.         CMP    CX,AX        ;Did the buffer fill?
  194.         MOV    DX,OFFSET FILE_TOO_BIG
  195.         JE    ERR_EXIT    ;If yes, it is too big
  196.         MOV    AH,3EH
  197.         INT    21H        ;Close the file
  198. NO_FILENAME:
  199.         PUSH    ES
  200.         PUSH    ES        ;Save file segment
  201.         MOV    AX,3524H    ;Get INT 24 vector
  202.         INT    21H
  203.         MOV    WORD PTR OLDINT24,BX  ;Store the offset
  204.         MOV    WORD PTR OLDINT24+2,ES;And the segment
  205.  
  206.         PUSH    CS
  207.         POP    DS
  208.         MOV    DX,OFFSET NEWINT24    ;Point to new vector
  209.         MOV    AX,2524H    ;Now change INT 24 vector
  210.         INT    21H    
  211.  
  212.         MOV    DX,OFFSET NEWINT23
  213.         MOV    AX,2523H    ;Set the INT 23 vector also
  214.         INT    21H
  215.  
  216.         POP    ES        ;Get back file segment
  217.         POP    DS
  218.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  219.         CALL    REDO_PROMPT    ;Draw the prompt line
  220.  
  221. ;-----------------------------------------------------------------------
  222. ; Here's the main loop.  It updates the screen, then reads a keystroke.
  223. ;-----------------------------------------------------------------------
  224. READ_A_KEY:
  225.         CMP    MARK_MODE,0    ;Is the mark state on?
  226.         JE    MARK_OFF    ;If not, skip this
  227.         OR    DIRTY_BITS,4    ;Refresh the current row
  228.         MOV    DX,CUR_POSN
  229.         CMP    SAVE_ROW,DH    ;Are we on the save row?
  230.         JE    SAME_ROW    ;If yes, then redo the row only
  231.         MOV    DIRTY_BITS,1    ;Refresh the whole screen
  232. SAME_ROW:
  233.         MOV    AX,CURSOR    ;Get cursor location
  234.         MOV    BX,MARK_HOME    ;Get the anchor mark position
  235.         CMP    AX,BX        ;Moving backward in file?
  236.         JAE    S1
  237.         MOV    MARK_START,AX    ;Switch start and end position
  238.         MOV    MARK_END,BX
  239.         JMP    SHORT MARK_OFF
  240. S1:
  241.         MOV    MARK_END,AX    ;Store start and end marks
  242.         MOV    MARK_START,BX
  243. MARK_OFF:
  244.         MOV    DX,CUR_POSN
  245.         MOV    SAVE_ROW,DH
  246.         CALL    SET_CURSOR    ;Position the cursor
  247.         TEST    DIRTY_BITS,1    ;Look at screen dirty bit
  248.         JZ    SCREEN_OK    ;If zero, screen is OK
  249.  
  250.         MOV    AH,1        ;Get keyboard status
  251.         INT    16H        ;Any keys ready?
  252.         JNZ    CURRENT_OK    ;If yes, skip the update
  253.         CALL    DISPLAY_SCREEN    ;Redraw the screen
  254.         MOV    DIRTY_BITS,0    ;Mark screen as OK
  255. SCREEN_OK:
  256.         TEST    DIRTY_BITS,4    ;Is the current line dirty?
  257.         JZ    CURRENT_OK    ;If not, take jump
  258.         CALL    DISPLAY_CURRENT    ;Redraw the current line
  259.         MOV    DIRTY_BITS,0    ;Mark screen as OK
  260. CURRENT_OK:
  261.         MOV    KP_CR,0
  262.         MOV    AH,10H        ;Read the next key
  263.         INT    16H
  264.         CMP    SRCH_FLG,0
  265.         JE    CKEXT
  266.         MOV    SRCH_FLG,0
  267.         MOV    DIRTY_BITS,1
  268. CKEXT:        CMP    AL,0        ;Is this an extended code?
  269.         JE    EXTENDED_CODE
  270.         CMP    AL,0E0H        ;Is this an extended code?
  271.         JNE    DO_BAD
  272.         CMP    AH,0
  273.         JNE    EXTENDED_CODE
  274. DO_BAD:
  275.         CMP    AH,0EH        ;Was it the backspace key?
  276.         JE    BACK_SPACE
  277.         CALL    INSERT_KEY    ;Put this character in the file
  278.         JMP    READ_A_KEY    ;Get another key
  279. BACK_SPACE:
  280.         CMP    CURSOR,0    ;At start of file?
  281.         JE    BAD_KEY        ;If at start, can't backspace
  282.         CALL    LEFT        ;Move left one space
  283.         CALL    DEL_CHAR    ;And delete the character
  284.         JMP    READ_A_KEY
  285. EXTENDED_CODE:
  286.         MOV    AL,0
  287.         CMP    AH,84H        ;Is it control PgUp?
  288.         JNE    NOT_TOP
  289.         CALL    TOP
  290.         JMP    READ_A_KEY
  291. NOT_TOP:
  292.         CMP    AH,76H        ;Is it control PgDn?
  293.         JNE    NOT_BOTTOM
  294.         CALL    BOTTOM
  295.         JMP    READ_A_KEY
  296. BAD_KEY:
  297.         MOV    AL,AH
  298.         JMP    SHORT DO_BAD
  299. NOT_BOTTOM:
  300.         CMP    AH,66H        ;Is it shift F9
  301.         JNE    NOT_RPT
  302.         CALL    FIND_STR
  303.         JMP    READ_A_KEY
  304. NOT_RPT:
  305.         CMP    AH,73H        ;Is it control left arrow?
  306.         JE    SH_LEFT
  307.         CMP    AH,74H        ;Is it control right arrow?
  308.         JE    SH_RIGHT
  309.         CMP    AH,53H        ;Skip high numbered keys
  310.         JA    BAD_KEY
  311.         XCHG    AH,AL
  312.         SUB    AL,3BH        ;Also skip low numbered keys
  313.         JC    BAD_KEY
  314.         SHL    AX,1        ;Make the code an offset
  315.         MOV    BX,AX        ;Put offset in BX
  316.         CALL    CS:DISPATCH_TABLE[BX] ;Call the key procedure
  317.         JMP    READ_A_KEY    ;Then read another key
  318.  
  319. ;-----------------------------------------------------------------------
  320. ; These two routines shift the display right or left to allow editing
  321. ; files which contain lines longer than 80 columns.
  322. ;-----------------------------------------------------------------------
  323. SH_RIGHT    PROC    NEAR
  324.         CMP    LEFT_MARGIN,255 - 8 ;Past max allowable margin?
  325.         JAE    NO_SHIFT    ;Then can't move any more
  326.         ADD    LEFT_MARGIN,8    ;This moves the margin over
  327. SH_RETURN:
  328.         CALL    CURSOR_COL    ;Compute column for cursor
  329.         MOV    DX,CUR_POSN
  330.         MOV    SAVE_COLUMN,DL    ;Save the current column
  331.         MOV    DIRTY_BITS,1    ;Redraw the screen
  332. NO_SHIFT:
  333.         JMP    READ_A_KEY
  334. SH_RIGHT    ENDP
  335.  
  336. SH_LEFT        PROC    NEAR
  337.         CMP    LEFT_MARGIN,0    ;At start of line already?
  338.         JE    NO_SHIFT    ;If yes, then don't shift
  339.         SUB    LEFT_MARGIN,8    ;Move the window over
  340.         JMP    SH_RETURN
  341. SH_LEFT        ENDP
  342.  
  343. ;-----------------------------------------------------------------------
  344. ; This moves the cursor to the top of the file.
  345. ;-----------------------------------------------------------------------
  346. TOP        PROC    NEAR
  347.         XOR    AX,AX        ;Get a zero into AX
  348.         MOV    CURSOR,AX    ;Cursor to start of file
  349.         MOV    TOP_OF_SCREEN,AX
  350.         MOV    LEFT_MARGIN,AL    ;Move to far left margin
  351.         MOV    DIRTY_BITS,1    ;Redraw the screen
  352.         MOV    CUR_POSN,AX    ;Home the cursor
  353.         MOV    SAVE_COLUMN,AL    ;Save the cursor column
  354.         RET
  355. TOP        ENDP
  356.  
  357. ;-----------------------------------------------------------------------
  358. ; This moves the cursor to the bottom of the file
  359. ;-----------------------------------------------------------------------
  360. BOTTOM        PROC    NEAR
  361.         MOV    DH,ROWS        ;Get screen size
  362.         MOV    SI,LAST_CHAR    ;Point to last character
  363.         DEC    SI
  364.         MOV    LEFT_MARGIN,0    ;Set window to start of line
  365.         CALL    LOCATE        ;Adjust the screen position
  366.         CALL    HOME        ;Move cursor to start of line
  367.         MOV    DIRTY_BITS,1    ;This will redraw the screen
  368.         RET
  369. BOTTOM        ENDP
  370.  
  371. ;-----------------------------------------------------------------------
  372. ; Search for a string
  373. ;-----------------------------------------------------------------------
  374. FIND_STR    PROC    NEAR
  375.         PUSH    DS
  376.         MOV    BX,CS
  377.         MOV    DS,BX
  378.         CMP    AH,66H        ;Is it shift F9
  379.         JE    RPT_FIND
  380.         MOV    DH,ROWS
  381.         INC    DH        ;Last row on the screen
  382.         XOR    DL,DL        ;First column
  383.         MOV    SI,OFFSET SRCH_PROMPT
  384.         CALL    TTY_STRING    ;Display search prompt
  385.         MOV    DX, OFFSET SRCH_MAX
  386.         MOV    AH,0Ah
  387.         INT    21h        ;Read input string
  388. RPT_FIND:
  389.         XOR    DX,DX
  390.         MOV    DL, BYTE PTR SRCH_SIZ
  391.         ADD    DX, OFFSET SRCH_STR
  392.         MOV    DI,DX
  393.         DEC    DI
  394.         MOV    SRCH_END,DI
  395.         XOR    DX,DX
  396.         MOV    SI,CURSOR
  397.         INC    SI
  398.         MOV    SRCH_BASE,SI
  399. S_REDO:        MOV    DI,OFFSET SRCH_STR
  400.         MOV    BX,SRCH_BASE
  401. S_CYCLE:    MOV    AL,[DI]
  402.         MOV    AH,AL        ;CONVERT AL TO OPPOSITE AND PUT IN AH
  403.         CMP    AL,65
  404.         JB    S_CMP
  405.         CMP    AL,90
  406.         JA    TSTLO
  407.         XOR    AH,20H
  408.         JMP    SHORT S_CMP
  409. TSTLO:        CMP    AL,97
  410.         JB    S_CMP
  411.         XOR    AH,20H
  412. S_CMP:        CMP    BX,LAST_CHAR
  413.         JA    END_MCH
  414.         CMP    AL,ES:[BX]
  415.         JE    S_MCH
  416.         CMP    AH,ES:[BX]
  417.         JE    S_MCH
  418.         CMP    DI,OFFSET SRCH_STR
  419.         JNE    S_REDO
  420.         INC    BX
  421.         CMP    WORD PTR ES:[BX]-1,LFCR
  422.         JNE    S_BX1
  423.         INC    DL
  424. S_BX1:        JMP    SHORT S_CMP
  425.         
  426. S_MCH:        INC    BX
  427.         CMP    DI,OFFSET SRCH_STR
  428.         JNE    NO_BSE
  429.         MOV    SRCH_BASE,BX
  430. NO_BSE:        ADD    DH,DL
  431.         XOR    DL,DL
  432.         CMP    DI,SRCH_END
  433.         JE    YEA_MCH
  434.         INC    DI
  435.         JMP    SHORT S_CYCLE
  436. YEA_MCH:    
  437.         MOV    SRCH_FLG,1
  438.         MOV    SI,SRCH_BASE
  439.         DEC    SI
  440.         MOV    SRCH_BASE,SI
  441.         MOV    CURSOR,SI
  442.         XOR    BX,BX
  443.         MOV    BL,BYTE PTR SRCH_SIZ
  444.         ADD    BX,SI
  445.         MOV    SRCH_END,BX
  446.         XOR    DL,DL
  447.         ADD    DX,CUR_POSN
  448.         CMP    DH,ROWS
  449.         JBE    NEW_S
  450.         XOR    DX,DX
  451. NEW_S:        POP    DS
  452.         CALL    LOCATE
  453.         MOV    DIRTY_BITS,1    ;This will redraw the screen
  454.         CALL    REDO_PROMPT
  455.         RET
  456. END_MCH:        
  457.         POP    DS
  458.         CALL    REDO_PROMPT
  459.         RET
  460. FIND_STR    ENDP
  461.  
  462. ;-----------------------------------------------------------------------
  463. ; This deletes from the cursor position to the end of line.
  464. ;-----------------------------------------------------------------------
  465. DEL_EOL        PROC    NEAR
  466.         MOV    CX,CUR_POSN
  467.         OR    CL,CL        ;At first column?
  468.         JZ    DEL_L        ;If yes, then do line delete function
  469.         MOV    LINE_FLAG,0
  470.         PUSH    CURSOR        ;Save starting cursor location
  471.         CALL    ENDD        ;Move the the end of line
  472.         POP    SI        ;Get back starting cursor
  473.         MOV    CX,CURSOR    ;Offset of the end of line
  474.         MOV    CURSOR,SI    ;Restore starting cursor
  475.         JMP    DEL_END        ;Delete characters to end
  476. DEL_EOL        ENDP
  477.  
  478.  
  479. ;-----------------------------------------------------------------------
  480. ; This deletes a line, placing it in the line buffer.
  481. ;-----------------------------------------------------------------------
  482. DEL_L        PROC    NEAR
  483.         MOV    LINE_FLAG,1
  484.         CALL    FIND_START    ;Find start of this line
  485.         MOV    CURSOR,SI    ;This will be the new cursor
  486.         PUSH    SI        ;Save the cursor position
  487.         CALL    FIND_NEXT    ;Find the next line
  488.         MOV    CX,SI        ;CX will hold line length
  489.         POP    SI        ;Get back new cursor location
  490. DEL_END:
  491.         SUB    CX,SI        ;Number of bytes on line
  492.         OR    CH,CH        ;Is line too long to fit
  493.         JZ    NOT_TOO_LONG
  494.         MOV    CX,100H        ;Only save 256 characters
  495. NOT_TOO_LONG:
  496.         MOV    LINE_LENGTH,CX    ;Store length of deleted line
  497.         JCXZ    NO_DEL_L
  498.         MOV    DI,OFFSET LINE_BUFFER ;Buffer for deleted line
  499.  
  500.         PUSH    CX
  501.         PUSH    ES
  502.         PUSH    CS
  503.         POP    ES        ;Line buffer is in CSEG
  504.         REP    MOVSB        ;Put deleted line in buffer
  505.         POP    ES        ;Get back file segment
  506.         POP    AX
  507.  
  508.         MOV    CX,LAST_CHAR    ;Get the file size
  509.         SUB    LAST_CHAR,AX    ;Subtract the deleted line
  510.         MOV    SI,CURSOR    ;Get new cursor location
  511.         MOV    DI,SI
  512.         ADD    SI,AX        ;SI points to end of file
  513.         SUB    CX,SI        ;Length of remaining file
  514.         JCXZ    NO_DEL_L
  515.         REP    MOVSB        ;Shift remainder of file up
  516. NO_DEL_L:
  517.         MOV    DX,CUR_POSN    ;Get cursor row/column
  518.         MOV    SI,CURSOR    ;Get cursor offset
  519.         CALL    LOCATE        ;Adjust the screen position
  520.         MOV    DIRTY_BITS,1    ;Redraw the screen
  521.         RET
  522. DEL_L        ENDP
  523.  
  524. ;-----------------------------------------------------------------------
  525. ; This undeletes a line by copying it from the line buffer into the file
  526. ;-----------------------------------------------------------------------
  527. UDEL_L        PROC    NEAR
  528.         CMP    LINE_FLAG,0    ;Is this an end of line only?
  529.         JE    UDEL_EOL    ;If yes, don't home the cursor
  530.         CALL    HOME        ;Move cursor to home
  531. UDEL_EOL:
  532.         MOV    AX,LINE_LENGTH    ;Length of deleted line
  533.         MOV    SI,OFFSET LINE_BUFFER
  534.         JMP    INSERT_STRING
  535. UDEL_L        ENDP
  536.  
  537. ;-----------------------------------------------------------------------
  538. ; These routines move the cursor left and right.
  539. ;-----------------------------------------------------------------------
  540. LEFT        PROC    NEAR
  541.         CMP    CURSOR,0    ;At start of file?
  542.         JZ    LR_NO_CHANGE    ;Then can't move left
  543.         MOV    DX,CUR_POSN
  544.         OR    DL,DL        ;At first column?
  545.         JZ    MOVE_UP        ;If yes, then move up one
  546.         DEC    CURSOR        ;Shift the cursor offset
  547. LR_RETURN:
  548.         CALL    CURSOR_COL    ;Compute column for cursor
  549.         MOV    SAVE_COLUMN,DL    ;Save the cursor column
  550. LR_NO_CHANGE:
  551.         MOV    UNDO_LENGTH,0
  552.         RET
  553. MOVE_UP:
  554.         CALL    UP        ;Move up to next row
  555.         JMP    SHORT ENDD    ;And move to end of line
  556. LEFT        ENDP
  557.  
  558. RIGHT        PROC    NEAR
  559.         MOV    SI,CURSOR
  560.         CMP    SI,LAST_CHAR    ;At end of file?
  561.         JE    LR_NO_CHANGE    ;If yes, then can't move
  562.         CMP    BYTE PTR [SI],CR;If CR
  563.         JNE    INC_RIGHT    ;If yes, then test LF
  564.         INC    SI
  565.         CMP    SI,LAST_CHAR    ;At end of file?
  566.         DEC    SI
  567.         JE    INC_RIGHT    ;If yes, then increment
  568.         CMP    BYTE PTR [SI+1],LF;If LF
  569.         JE    MOVE_DOWN    ;If yes, then move to next line
  570. INC_RIGHT:
  571.         INC    CURSOR        ;Advance the cursor
  572.         JMP    LR_RETURN
  573. MOVE_DOWN:
  574.         CALL    HOME        ;Move to start of line
  575.         JMP    DOWN        ;And move down one row
  576. RIGHT        ENDP
  577.  
  578. ;-----------------------------------------------------------------------
  579. ; This moves the cursor to the start of the current line.
  580. ;-----------------------------------------------------------------------
  581. HOME        PROC    NEAR
  582.         CALL    FIND_START    ;Find start of line
  583.         MOV    CURSOR,SI    ;Save the new cursor
  584.         MOV    SAVE_COLUMN,0    ;Save the cursor column
  585.         MOV    BYTE PTR CUR_POSN,0 ;Store column number
  586.         RET
  587. HOME        ENDP
  588.  
  589. ;-----------------------------------------------------------------------
  590. ; This moves the cursor to the end of the current line
  591. ;-----------------------------------------------------------------------
  592. ENDD        PROC    NEAR
  593.         MOV    SI,CURSOR
  594.         CALL    FIND_EOL    ;Find end of this line
  595.         MOV    CURSOR,SI    ;Store the new cursor
  596.         CALL    CURSOR_COL    ;Compute the correct column
  597.         MOV    SAVE_COLUMN,DL    ;Save the cursor column
  598.         RET
  599. ENDD        ENDP
  600.  
  601. ;-----------------------------------------------------------------------
  602. ; This moves the cursor up one row.  If the cursor is at the first row,
  603. ; the screen is scrolled down.
  604. ;-----------------------------------------------------------------------
  605. UP        PROC    NEAR
  606.         MOV    UNDO_LENGTH,0
  607.         MOV    DX,CUR_POSN
  608.         MOV    SI,CURSOR
  609.         OR    DH,DH        ;At top row already?
  610.         JZ    SCREEN_DN    ;If yes, then scroll down
  611.         DEC    DH        ;Move cursor up one row
  612.         CALL    FIND_CR        ;Find the beginning of this row
  613.         MOV    CURSOR,SI
  614.         CALL    FIND_START    ;Find start of this row
  615.         MOV    CURSOR,SI
  616.         CALL    SHIFT_RIGHT    ;Skip over to current column
  617. AT_TOP:
  618.         RET
  619. SCREEN_DN:
  620.         MOV    SI,TOP_OF_SCREEN
  621.         OR    SI,SI        ;At start of file?
  622.         JZ    AT_TOP        ;If at top, then do nothing
  623.         CALL    FIND_PREVIOUS    ;Find the preceeding line
  624.         MOV    TOP_OF_SCREEN,SI;Save new top of screen
  625.         MOV    SI,CURSOR
  626.         CALL    FIND_PREVIOUS    ;Find the preceeding line
  627.         MOV    CURSOR,SI    ;This is the new cursor
  628. SHIFT_RET:
  629.         MOV    DIRTY_BITS,1    ;Need to redraw screen
  630.         MOV    SI,CURSOR
  631.         MOV    DX,CUR_POSN
  632.         JMP    SHIFT_RIGHT    ;Move cursor to current column
  633. UP        ENDP
  634.  
  635. ;-----------------------------------------------------------------------
  636. ; This moves the cursor down one row.  When the last row is reached,
  637. ; the screen is shifted up one row.
  638. ;-----------------------------------------------------------------------
  639. DOWN        PROC    NEAR
  640.         MOV    UNDO_LENGTH,0
  641.         MOV    DX,CUR_POSN
  642.         CMP    DH,ROWS        ;At bottom row already?
  643.         MOV    SI,CURSOR    ;Get position in file
  644.         JE    SCREEN_UP    ;If at bottom, then scroll up
  645.         CALL    FIND_NEXT    ;Find the start of next line
  646.         JC    DOWN_RET    ;If no more lines, then return
  647.         MOV    CURSOR,SI
  648.         INC    DH        ;Advance cursor to next row
  649.         CALL    SHIFT_RIGHT    ;Move cursor to current column
  650. DOWN_RET:
  651.         RET
  652. SCREEN_UP:
  653.         CMP    SI,LAST_CHAR    ;Get cursor offset
  654.         JE    DOWN_RET
  655.         CALL    FIND_START    ;Find the start of this line
  656.         MOV    CURSOR,SI    ;This is the new cursor
  657.         CALL    FIND_NEXT    ;Find the offset of next line
  658.         JC    SHIFT_RET    ;If no more lines then return
  659.         MOV    CURSOR,SI    ;This is the new cursor
  660.         MOV    SI,TOP_OF_SCREEN;Get the start of the top row
  661.         CALL    FIND_NEXT    ;And find the next line
  662.         MOV    TOP_OF_SCREEN,SI;Store the new top of screen
  663.         JMP    SHIFT_RET
  664. DOWN        ENDP
  665.  
  666. ;-----------------------------------------------------------------------
  667. ; These two routines move the screen one page at a time by calling the
  668. ; UP and DOWN procedures.
  669. ;-----------------------------------------------------------------------
  670. PGDN        PROC    NEAR
  671.         MOV    PAGE_PROC,OFFSET DOWN
  672. PAGE_UP_DN:
  673.         MOV    CL,ROWS        ;Get length of the screen
  674.         SUB    CL,5        ;Don't page a full screen
  675.         XOR    CH,CH        ;Make it a word
  676. PAGE_LOOP:
  677.         PUSH    CX
  678.         CALL    PAGE_PROC    ;Move the cursor down
  679.         POP    CX
  680.         LOOP    PAGE_LOOP    ;Loop for one page length
  681.         RET
  682. PGDN        ENDP
  683.  
  684. PGUP        PROC    NEAR
  685.         MOV    PAGE_PROC,OFFSET UP
  686.         JMP    PAGE_UP_DN
  687. PGUP        ENDP
  688.  
  689. ;-----------------------------------------------------------------------
  690. ; This toggles the insert/overstrike mode.
  691. ;-----------------------------------------------------------------------
  692. INSERT        PROC    NEAR
  693.         NOT    INSERT_MODE    ;Toggle the switch
  694.         JMP    REDO_PROMPT    ;Redraw the insert status
  695. INSERT        ENDP
  696.  
  697. ;-----------------------------------------------------------------------
  698. ; This deletes the character at the cursor by shifting the remaining 
  699. ; characters forward.
  700. ;-----------------------------------------------------------------------
  701. DEL_CHAR    PROC    NEAR
  702.         MOV    CX,LAST_CHAR
  703.         MOV    SI,CURSOR
  704.         MOV    DI,SI
  705.         CMP    SI,CX        ;Are we at end of file?
  706.         JAE    NO_DEL        ;If yes, then don't delete
  707.         LODSB
  708.         CALL    SAVE_CHAR    ;Save it for UNDO function
  709.         MOV    AH,[SI]        ;Look at the next character also
  710.         PUSH    AX        ;Save character were deleting
  711.         DEC    LAST_CHAR    ;Shorten the file by one
  712.         SUB    CX,SI
  713.         REP    MOVSB        ;Move file down one notch
  714.  
  715.         POP    AX        ;Get back character we deleted
  716.         CMP    AL,CR        ;Did we delete a CR?
  717.         JE    COMBINE
  718.         OR    DIRTY_BITS,4    ;Current line is dirty
  719. NO_DEL:
  720.         RET
  721. COMBINE:
  722.         CMP    AH,LF        ;Was the next character a LF?
  723.         JNE    NO_DEL_LF
  724.         CALL    DEL_CHAR    ;Now delete the line feed
  725. NO_DEL_LF:
  726.         CALL    DISPLAY_BOTTOM    ;Repaint bottom of the screen
  727.         MOV    DX,CUR_POSN
  728.         MOV    SAVE_COLUMN,DL    ;Save the cursor column
  729.         RET
  730. DEL_CHAR    ENDP
  731.  
  732. ;-----------------------------------------------------------------------
  733. ; This toggles the mark state and resets the paste buffer pointers.
  734. ;-----------------------------------------------------------------------
  735. MARK        PROC    NEAR
  736.         XOR    AX,AX
  737.         NOT    MARK_MODE    ;Toggle the mode flag
  738.         CMP    MARK_MODE,AL    ;Turning mode ON?
  739.         JNE    MARK_ON
  740.         MOV    DIRTY_BITS,1    ;Need to redraw the screen
  741.         MOV    MARK_START,0FFFFH
  742.         JMP    SHORT MARK_RET
  743. MARK_ON:
  744.         MOV    AX,CURSOR    ;Get the cursor offset
  745.         MOV    MARK_START,AX    ;Start of marked range
  746. MARK_RET:
  747.         MOV    MARK_END,  AX    ;End of marked range
  748.         MOV    MARK_HOME, AX    ;Center of marked range
  749.         RET
  750. MARK        ENDP
  751.  
  752. ;-----------------------------------------------------------------------
  753. ; This removes the marked text and places it in the paste buffer
  754. ;-----------------------------------------------------------------------
  755. CUT        PROC    NEAR
  756.         CMP    MARK_MODE,0    ;Is the mark mode on?
  757.         JE    NO_MARK        ;If not, then do nothing
  758.         MOV    CX,MARK_END    ;Get end of mark region
  759.         MOV    SI,MARK_START    ;Get start of mark region
  760.         SUB    CX,SI        ;Number of bytes selected
  761.         MOV    PASTE_SIZE,CX
  762.         JCXZ    NO_MARK
  763.         XOR    DI,DI        ;Point to paste bufferf
  764.  
  765.         PUSH    CX
  766.         PUSH    ES
  767.         MOV    ES,PASTE_SEG    ;Get the paste segment
  768.         REP    MOVSB        ;Put deleted text in buffer
  769.         POP    ES
  770.         POP    AX
  771.  
  772.         MOV    CX,LAST_CHAR
  773.         SUB    LAST_CHAR,AX    ;Shorten the file this much
  774.         MOV    DI,MARK_START
  775.         MOV    SI,MARK_END
  776.         SUB    CX,SI
  777.         JCXZ    NO_DELETE
  778.         REP    MOVSB        ;Shorten the file
  779. NO_DELETE:
  780.         MOV    DX,CUR_POSN
  781.         MOV    SI,MARK_START
  782.         CALL    LOCATE        ;Adjust the screen position
  783.         CALL    MARK        ;This turns off select
  784. NO_MARK:
  785.         RET
  786. CUT        ENDP
  787.  
  788. ;-----------------------------------------------------------------------
  789. ; This copies the paste buffer into the file at the cursor location
  790. ;-----------------------------------------------------------------------
  791. PASTE        PROC    NEAR
  792.         MOV    AX,PASTE_SIZE    ;Number of characters in buffer
  793.         OR    AX,AX        ;Any there?
  794.         JZ    NO_PASTE    ;If not, nothing to paste
  795.         MOV    SI,CURSOR    ;Get cursor location
  796.         PUSH    AX
  797.         PUSH    SI
  798.         CALL    OPEN_SPACE    ;Make room for new characters
  799.         POP    DI
  800.         POP    CX
  801.         JC    NO_PASTE    ;If no room, just exit
  802.         XOR    SI,SI        ;Point to paste buffer
  803.         PUSH    DS
  804.         MOV    DS,PASTE_SEG    ;Segment of paste buffer
  805.         REP    MOVSB        ;Copy in the new characters
  806.         POP    DS
  807.         MOV    SI,DI
  808.         MOV    CURSOR,SI    ;Cursor moved to end of insert
  809.         MOV    DX,CUR_POSN    ;Get current cursor row
  810.         CALL    LOCATE        ;Adjust the screen position
  811.         MOV    DIRTY_BITS,1    ;Redraw the screen
  812. NO_PASTE:
  813.         RET
  814. PASTE        ENDP
  815.  
  816. ;-----------------------------------------------------------------------
  817. ; This prints the marked text.  If printer fails, it is canceled.
  818. ;-----------------------------------------------------------------------
  819. PRINT        PROC    NEAR
  820.         CMP    MARK_MODE,0    ;Is mark mode on?
  821.         JE    PRINT_RET    ;If not, nothing to print
  822.         MOV    CX,MARK_END    ;End of marked region
  823.         MOV    SI,MARK_START    ;Start of marked region
  824.         SUB    CX,SI        ;Number of bytes selected
  825.         JCXZ    PRINT_DONE    ;If nothing to print, return
  826.  
  827.         MOV    AH,2
  828.         XOR    DX,DX        ;Select printer 0
  829.         INT    17H        ;Get printer status
  830.         TEST    AH,10000000B    ;Is busy bit set?
  831.         JZ    PRINT_DONE
  832.         TEST    AH,00100000B    ;Is printer out of paper?
  833.         JNZ    PRINT_DONE
  834. PRINT_LOOP:
  835.         LODSB
  836.         XOR    AH,AH
  837.         INT    17H        ;Print the character
  838.         ROR    AH,1        ;Check time out bit
  839.         JC    PRINT_DONE    ;If set, quit printing
  840.         LOOP    PRINT_LOOP
  841.         MOV    AL,CR
  842.         XOR    AH,0
  843.         INT    17H        ;Finish with a CR
  844. PRINT_DONE:
  845.         CALL    MARK        ;Turn off the mark state
  846. PRINT_RET:
  847.         RET
  848. PRINT        ENDP
  849.  
  850. ;-----------------------------------------------------------------------
  851. ; This command restores any characters which have recently been deleted.
  852. ;-----------------------------------------------------------------------
  853. UNDO        PROC    NEAR
  854.         XOR    AX,AX
  855.         XCHG    AX,UNDO_LENGTH    ;Get buffer length
  856.         MOV    SI,OFFSET UNDO_BUFFER
  857.         JMP    INSERT_STRING
  858. UNDO        ENDP
  859.  
  860. ;-----------------------------------------------------------------------
  861. ; This inserts AX characters from CS:SI into the file.
  862. ;-----------------------------------------------------------------------
  863. INSERT_STRING    PROC    NEAR
  864.         PUSH    SI        ;Save string buffer
  865.         MOV    SI,CURSOR    ;Get cursor offset
  866.         PUSH    AX        ;Save length of string
  867.         PUSH    SI
  868.         CALL    OPEN_SPACE    ;Make space to insert string
  869.         POP    DI        ;Get back cursor position
  870.         POP    CX        ;Get back string length
  871.         POP    SI        ;Get back string buffer
  872.         JC    NO_SPACE    ;If no space available, exit
  873.  
  874.         PUSH    DS
  875.         PUSH    CS
  876.         POP    DS
  877.         ASSUME    DS:CSEG
  878.         REP    MOVSB        ;Copy the characters in
  879.         MOV    SI,CURSOR    ;Get the new cursor offset
  880.         MOV    DX,CUR_POSN    ;Also get the current row
  881.         MOV    DIRTY_BITS,1    ;And redraw the screen
  882.         POP    DS
  883.         ASSUME    DS:NOTHING
  884.         CALL    LOCATE        ;Adjust the screen position
  885. NO_SPACE:
  886.         RET
  887. INSERT_STRING    ENDP
  888.  
  889. ;-----------------------------------------------------------------------
  890. ; This adds a character to the undo buffer.
  891. ;-----------------------------------------------------------------------
  892. SAVE_CHAR    PROC    NEAR
  893.         MOV    BX,UNDO_LENGTH
  894.         OR    BH,BH        ;Is buffer filled?
  895.         JNZ    NO_SAVE
  896.         INC    UNDO_LENGTH
  897.         MOV    BYTE PTR CS:UNDO_BUFFER[BX],AL
  898. NO_SAVE:
  899.         RET
  900. SAVE_CHAR    ENDP
  901.  
  902. ;-----------------------------------------------------------------------
  903. ; This prompts for a verify keystroke then exits without saving the file
  904. ;-----------------------------------------------------------------------
  905. ABORT        PROC    NEAR
  906.         ASSUME    DS:CSEG
  907.         PUSH    CS
  908.         POP    DS
  909.         MOV    DH,ROWS        ;Last row on display
  910.         INC    DH        ;Bottom row of screen
  911.         XOR    DL,DL        ;First column
  912. FINISHED:
  913.         MOV     AH,ORGATR
  914.         MOV    NORMAL,AH    ;Go back to black and white
  915.         MOV    DH,ROWS        ;Move to last row on screen
  916.         XOR    DL,DL        ;And column zero
  917.         CALL    SET_CURSOR
  918.         INC    DH
  919.         CALL    ERASE_EOL    ;Erase the last row
  920. EXIT_TO_DOS:
  921.         PUSH    CS
  922.         POP    DS        ;Point to code segment
  923.         MOV    AX,4C00H
  924.         INT    21H
  925.  
  926. ABORT        ENDP
  927.  
  928. ;-----------------------------------------------------------------------
  929. ; This prompts for a filename then writes the file.  The original file
  930. ; is renamed to filename.BAK.  If an invalid filename is entered, the 
  931. ; speaker is beeped.
  932. ;-----------------------------------------------------------------------
  933. EXIT        PROC    NEAR
  934.  
  935.         PUSH    DS
  936.         PUSH    ES
  937.         MOV    AX,CS
  938.         MOV    DS,AX
  939.         MOV    ES,AX
  940.         ASSUME    DS:CSEG, ES:CSEG
  941. NEXT_LETTER:
  942.         MOV    DH,ROWS
  943.         INC    DH        ;Last row on the screen
  944.         XOR    DL,DL        ;First column
  945.         MOV    SI,OFFSET SAVE_MESS
  946.         PUSH    DX
  947.         CALL    TTY_STRING    ;Display a prompt
  948.         POP    DX
  949.         ADD    DL,9        ;Move right 9 spaces
  950.         MOV    SI,NAME_POINTER
  951.         CALL    TTY_STRING    ;Display the filename
  952.  
  953.         XOR    AH,AH        ;Read the next key
  954.         INT    16H
  955.         MOV    DI,NAME_END    ;This points to last letter
  956.         OR    AL,AL        ;Is it a real character?
  957.         JZ    NEXT_LETTER    ;Ignore special keys
  958.         CMP    AL,27        ;Is it escape?
  959.         JNE    NOT_ESCAPE
  960.  
  961.         MOV    DIRTY_BITS,1    ;Redraw the screen
  962.         POP    ES        ;Get back file segments
  963.         POP    DS
  964.         JMP    REDO_PROMPT    ;Redraw the prompt
  965. NOT_ESCAPE:
  966.         CMP    AL,CR        ;Is it CR?
  967.         JE    GOT_NAME
  968.         CMP    AL,8        ;Is it a backspace?
  969.         JNE    NORMAL_LETTER
  970.         CMP    DI,NAME_POINTER    ;At first letter?
  971.         JLE    NEXT_LETTER    ;If yes, dont erase it
  972.         MOV    BYTE PTR [DI-1],0
  973.         DEC    NAME_END
  974.         JMP    NEXT_LETTER
  975. NORMAL_LETTER:
  976.         CMP    DI,81H + 65    ;Too many letters?
  977.         JG    NEXT_LETTER    ;If yes, ignore them
  978.         XOR    AH,AH
  979.         STOSW            ;Store the new letter
  980.         INC    NAME_END    ;Name is one character longer
  981.         JMP    NEXT_LETTER    ;Read another keystroke
  982. GOT_NAME:
  983.         MOV    DX,NAME_POINTER    ;Point to the filename
  984.         MOV    AX,4300H    ;Get the files attribute
  985.         INT    21H
  986.         JNC    NAME_OK        ;If no error, filename is OK
  987.         CMP    AX,3        ;Was it path not found error?
  988.         JE    BAD_NAME    ;If yes, filename was bad
  989. NAME_OK:
  990.         MOV    SI,OFFSET DOT_$$$    ;Point to the ".$$$"
  991.         MOV    DI,OFFSET NAME_DOT_$$$
  992.         CALL    CHG_EXTENSION        ;Add the new extension
  993.  
  994.         MOV    DX,OFFSET NAME_DOT_$$$    ;Point to the temp filename
  995.         MOV    AH,3CH            ;Function to create file
  996.         MOV    CX,0020H        ;Attribute for new file
  997.         INT    21H            ;Try to create the file
  998.         JNC    NAME_WAS_OK        ;Continue if name was OK
  999. BAD_NAME:
  1000.         MOV    AX,0E07H    ;Write a bell character
  1001.         INT    10H        ;BIOS tty service
  1002.         JMP    NEXT_LETTER    ;Get another letter
  1003. WRITE_ERROR:
  1004.         MOV    AH,3EH        ;Close the file
  1005.         INT    21H
  1006.         JMP    BAD_NAME    ;Filename must be bad
  1007. NAME_WAS_OK:
  1008.         XOR    DX,DX        ;This is the file buffer
  1009.         MOV    CX,LAST_CHAR    ;Number of chars in file
  1010.         MOV    DI,CX
  1011.         MOV    BX,AX        ;This is the handle
  1012.         MOV    AH,40H        ;Write to the file
  1013.         POP    DS        ;Recover buffer segment
  1014.         INT    21H        ;Write the buffer contents
  1015.         POP    DS
  1016.         JC    WRITE_ERROR    ;Exit on a write error
  1017.         CMP    AX,CX        ;Was entire file written?
  1018.         JNE    WRITE_ERROR    ;If not, exit
  1019.  
  1020.         PUSH    CS
  1021.         POP    DS        ;Get the code segment
  1022.         MOV    AH,3EH
  1023.         INT    21H            ;Close the temp file
  1024.         MOV    SI,OFFSET DOT_BAK    ;Point to the ".BAK"
  1025.         MOV    DI,OFFSET NAME_DOT_BAK
  1026.         CALL    CHG_EXTENSION        ;Make the backup filename
  1027.  
  1028.         MOV    DX,OFFSET NAME_DOT_BAK    ;Point to the backup name
  1029.         MOV    AH,41H
  1030.         INT    21H            ;Delete existing backup file
  1031.         MOV    DI,OFFSET NAME_DOT_BAK
  1032.         MOV    DX,NAME_POINTER
  1033.         MOV    AH,56H
  1034.         INT    21H
  1035.  
  1036.         MOV    DI,NAME_POINTER    ;Point to new filename
  1037.         MOV    DX,OFFSET NAME_DOT_$$$ ;Point to temporary file
  1038.         MOV    AH,56H        ;Rename temp to new file
  1039.         INT    21H        ;DOS function to rename
  1040.         POP    AX        ;Restore the stack
  1041.         POP    AX
  1042.         JMP    FINISHED
  1043. EXIT        ENDP
  1044.  
  1045. ;-----------------------------------------------------------------------
  1046. ; This subroutine displays a character by writing directly
  1047. ; to the screen buffer.  To avoid screen noise (snow) on the color
  1048. ; card, the horizontal retrace has to be monitored.
  1049. ;-----------------------------------------------------------------------
  1050. WRITE_INVERSE    PROC    NEAR
  1051.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  1052.         MOV    BH,INVERSE    ;Attribute for inverse video
  1053.         JMP    SHORT WRITE_SCREEN
  1054. WRITE_NORMAL:
  1055.         MOV    BH,NORMAL    ;Attribute for normal video
  1056.         JMP    SHORT WRITE_SCREEN
  1057. WRITE_FIND:
  1058.         MOV    BH,SRCH_CLR    ;Attribute for find string
  1059. WRITE_SCREEN:
  1060.         MOV    BL,AL        ;Save the character
  1061.         PUSH    ES
  1062.         MOV    DX,STATUS_REG     ;Retrieve status register
  1063.         MOV    ES,VIDEO_SEG    ;Get segment of video buffer
  1064. HWAIT:
  1065.         IN    AL,DX        ;Get video status
  1066.         ROR    AL,1        ;Look at horizontal retrace
  1067.         JNC    HWAIT        ;Wait for retrace
  1068. WRITE_IT:
  1069.         MOV    AX,BX        ;Get the character/attribute
  1070.         STOSW            ;Write the character
  1071.         POP    ES
  1072.         RET
  1073. WRITE_INVERSE    ENDP
  1074.  
  1075. ;-----------------------------------------------------------------------
  1076. ; This moves the cursor to the row/column in DX.
  1077. ;-----------------------------------------------------------------------
  1078. SET_CURSOR    PROC    NEAR
  1079.         XOR    BH,BH        ;Were using page zero
  1080.         MOV    AH,2        ;BIOS set cursor function
  1081.         INT    10H
  1082.         RET
  1083. SET_CURSOR    ENDP
  1084.  
  1085. ;-----------------------------------------------------------------------
  1086. ; This computes the video buffer offset for the row/column in DX
  1087. ;----------------------------------------------------------------------
  1088. POSITION    PROC    NEAR
  1089.         MOV    AX,COLUMNS    ;Take columns per row
  1090.         MUL    DH        ;Times row number
  1091.         XOR    DH,DH
  1092.         ADD    AX,DX        ;Add in the column number
  1093.         SHL    AX,1        ;Times 2 for offset
  1094.         MOV    DI,AX        ;Return result in DI
  1095.         RET
  1096. POSITION    ENDP
  1097.  
  1098. ;-----------------------------------------------------------------------
  1099. ; This erases from the location in DX to the right edge of the screen
  1100. ;-----------------------------------------------------------------------
  1101. ERASE_EOL    PROC    NEAR
  1102.         CALL    POSITION    ;Find screen offset
  1103.         MOV    CX,COLUMNS    ;Get screen size
  1104.         SUB    CL,DL        ;Subtract current position
  1105.         JCXZ    NO_CLEAR
  1106. ERASE_LOOP:
  1107.         MOV    AL," "        ;Write blanks to erase
  1108.         CALL    WRITE_NORMAL    ;Display it
  1109.         LOOP    ERASE_LOOP
  1110. NO_CLEAR:    RET
  1111. ERASE_EOL    ENDP
  1112.  
  1113. ;-----------------------------------------------------------------------
  1114. ; This displays the function key prompt and insert mode state
  1115. ;-----------------------------------------------------------------------
  1116. REDO_PROMPT    PROC    NEAR
  1117.         ASSUME    DS:NOTHING, ES:NOTHING
  1118.         PUSH    DS
  1119.         PUSH    CS
  1120.         POP    DS
  1121.         ASSUME    DS:CSEG
  1122.         MOV    DH,ROWS        ;Put prompt at last row
  1123.         INC    DH
  1124.         XOR    DL,DL        ;And column 0
  1125.         CALL    POSITION    ;Convert to screen offset
  1126.         MOV    SI,OFFSET PROMPT_STRING
  1127. KEY_LOOP:
  1128.         MOV    AL,"F"        ;Display an "F"
  1129.         CALL    WRITE_NORMAL
  1130.         LODSB
  1131.         OR    AL,AL        ;Last key in prompt?
  1132.         JZ    PROMPT_DONE
  1133.         CALL    WRITE_NORMAL
  1134.  
  1135.         CMP    BYTE PTR CS:[SI],"0"    ;Is it F10?
  1136.         JNE    TEXT_LOOP
  1137.         LODSB
  1138.         CALL    WRITE_NORMAL
  1139. TEXT_LOOP:
  1140.         LODSB
  1141.         OR    AL,AL        ;Last letter in word?
  1142.         JNZ    WRITE_CHAR
  1143.  
  1144.         MOV    AL," "        ;Display a space
  1145.         CALL    WRITE_NORMAL
  1146.         JMP    KEY_LOOP
  1147. WRITE_CHAR:
  1148.         CALL    WRITE_INVERSE    ;Display the letter
  1149.         JMP    TEXT_LOOP    ;Do the next letter
  1150. PROMPT_DONE:
  1151.         MOV    DH,ROWS
  1152.         INC    DH        ;Get to last row on screen
  1153.         MOV    DL,PROMPT_LENGTH + 9
  1154.         CALL    ERASE_EOL    ;Erase to the end of this row
  1155.         MOV    AL,"O"        ;Write an "O"
  1156.         CMP    INSERT_MODE,0    ;In insert mode?
  1157.         JE    OVERSTRIKE
  1158.         MOV    AL,"I"        ;Write an "I"
  1159. OVERSTRIKE:
  1160.         DEC    DI        ;Backup one character position
  1161.         DEC    DI
  1162.         CALL    WRITE_NORMAL
  1163.         POP    DS
  1164.         RET
  1165. REDO_PROMPT    ENDP
  1166.  
  1167. ;-----------------------------------------------------------------------
  1168. ; This displays the file buffer on the screen.
  1169. ;-----------------------------------------------------------------------
  1170. DISPLAY_SCREEN    PROC    NEAR
  1171.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  1172.         MOV    SI,TOP_OF_SCREEN;Point to first char on screen
  1173.         XOR    DH,DH        ;Start at first row
  1174.         JMP    SHORT NEXT_ROW
  1175. DISPLAY_BOTTOM:                ;This redraws the bottom only
  1176.         CALL    FIND_START    ;Find first character on this row
  1177.         MOV    DX,CUR_POSN    ;Get current cursor row
  1178. NEXT_ROW:
  1179.         PUSH    DX
  1180.         CALL    DISPLAY_LINE    ;Display a line
  1181.         POP    DX
  1182.         INC    DH        ;Move to the next row
  1183.         CMP    DH,ROWS        ;At end of screen yet?
  1184.         JBE    NEXT_ROW    ;Do all the rows
  1185.         RET
  1186. DISPLAY_SCREEN    ENDP
  1187.  
  1188. ;-----------------------------------------------------------------------
  1189. ; This subroutine displays a single line to the screen. DH holds the 
  1190. ; row number, SI has the offset into the file buffer. Tabs are expanded.
  1191. ; Adjustment is made for side shift.
  1192. ;-----------------------------------------------------------------------
  1193. DISPLAY_CURRENT    PROC    NEAR
  1194.         CALL    FIND_START
  1195.         MOV    DX,CUR_POSN
  1196. DISPLAY_LINE:
  1197.         XOR    DL,DL        ;Start at column zero
  1198.         MOV    MARGIN_COUNT,DL
  1199.         MOV    CX,DX        ;Use CL to count the columns
  1200.         CALL    POSITION    ;Compute offset into video
  1201. NEXT_CHAR:
  1202.         CMP    SI,LAST_CHAR    ;At end of file?
  1203.         JAE    LINE_DONE
  1204.         LODSB            ;Get next character
  1205.         CMP    AL,CR        ;Is it a carriage return?
  1206.         JE    FOUND_CR    ;Quit when a CR is found
  1207.         CMP    AL,TAB        ;Is this a Tab character
  1208.         JE    EXPAND_TAB    ;If yes, expand to spaces
  1209. DO_PUT:
  1210.         CALL    PUT_CHAR    ;Put character onto screen
  1211. TAB_DONE:
  1212.         CMP    CL,COLUMNSB    ;At right edge of screen?
  1213.         JB    NEXT_CHAR
  1214. LN_OVF:        CMP    BYTE PTR [SI],CR
  1215.         JNE    DO_DIA
  1216.         INC     SI
  1217.         CMP    SI,LAST_CHAR    ;At end of file?
  1218.         JAE    NOT_BEYOUND
  1219.         CMP    BYTE PTR [SI],LF;Is this the end of the line?
  1220.         DEC    SI
  1221.         JE    NOT_BEYOUND
  1222. DO_DIA:        DEC    DI        ;Backup one character
  1223.         DEC    DI
  1224.         MOV    AL,4        ;Show a diamond
  1225.         CALL    WRITE_INVERSE    ;In inverse video
  1226. NOT_BEYOUND:
  1227.         JMP    FIND_NEXT    ;Find start of next line
  1228. FOUND_CR:
  1229.         LODSB            ;Look at the next character
  1230.         CMP    AL,LF        ;Is it a line feed?
  1231.         JE    LINE_DONE
  1232.         MOV    AL,CR
  1233.         DEC    SI
  1234.         JMP    SHORT DO_PUT
  1235. LINE_DONE:
  1236.         MOV    DX,CX
  1237.         JMP    ERASE_EOL    ;Erase the rest of the line
  1238. EXPAND_TAB:
  1239.         MOV    AL," "        ;Convert Tabs to spaces
  1240.         CALL    PUT_CHAR
  1241.         MOV    AL,MARGIN_COUNT
  1242.         ADD    AL,CL
  1243.         TEST    AL,00000111B    ;At even multiple of eight?
  1244.         JNZ    EXPAND_TAB    ;If not keep adding spaces
  1245.         JMP    TAB_DONE
  1246. DISPLAY_CURRENT    ENDP
  1247.  
  1248. ;-----------------------------------------------------------------------
  1249. ; This displays a single character to the screen.  If the character is 
  1250. ; marked, it is shown in inverse video.  Characters outside the current
  1251. ; margin are not displayed. Characters left of the margin are skipped.
  1252. ;-----------------------------------------------------------------------
  1253. PUT_CHAR    PROC    NEAR
  1254.         MOV    BL,MARGIN_COUNT    ;Get distance to left margin
  1255.         CMP    BL,LEFT_MARGIN    ;Are we inside left margin?
  1256.         JAE    IN_WINDOW    ;If yes, show the character
  1257.         INC    BL
  1258.         MOV    MARGIN_COUNT,BL
  1259.         RET
  1260. IN_WINDOW:    CMP    SRCH_FLG,0
  1261.         JE    CKM
  1262.         CMP    SI,SRCH_BASE
  1263.         JBE    CKM
  1264.         CMP    SI,SRCH_END
  1265.         JA    CKM
  1266.         CALL    WRITE_FIND
  1267.         JMP    SHORT NEXT_COL
  1268. CKM:
  1269.         CMP    SI,MARK_START    ;Is this character marked?
  1270.         JBE    NOT_MARKED
  1271.         CMP    SI,MARK_END
  1272.         JA    NOT_MARKED
  1273.         CALL    WRITE_INVERSE    ;Marked characters shown inverse
  1274.         JMP    SHORT NEXT_COL
  1275. NOT_MARKED:
  1276.         CALL    WRITE_NORMAL
  1277. NEXT_COL:
  1278.         INC    CL        ;Increment the column count
  1279.         RET
  1280. PUT_CHAR    ENDP
  1281.  
  1282. ;-----------------------------------------------------------------------
  1283. ; This routine adds a character into the file.  In insert mode, remaining
  1284. ; characters are pushed forward. If a CR is inserted, a LF is added also.
  1285. ;-----------------------------------------------------------------------
  1286. INSERT_KEY    PROC    NEAR
  1287.         MOV    SI,CURSOR
  1288.         CMP    AL,CR        ;Was this a carriage return
  1289.         JNE    CK_INS
  1290.         CMP    AH,1CH
  1291.         JE    NEW_LINE
  1292. CK_INS:
  1293.         MOV    SI,CURSOR
  1294.         CMP    INSERT_MODE,0    ;In insert mode?
  1295.         JNE    INSERT_CHAR
  1296.         CMP    SI,LAST_CHAR    ;At end of file?
  1297.         JE    INSERT_CHAR
  1298.         CMP    BYTE PTR [SI],CR
  1299.         INC    SI
  1300.         CMP    SI,LAST_CHAR    ;At end of file?
  1301.         DEC    SI
  1302.         JE    INSERT_CHAR
  1303.         CMP    BYTE PTR [SI+1],LF;At end of line?
  1304.         JE    INSERT_CHAR
  1305.         MOV    DI,SI
  1306.         XCHG    DS:[SI],AL    ;Switch new character for old one
  1307.         CALL    SAVE_CHAR    ;Store the old character
  1308.         JMP    SHORT ADVANCE
  1309. INSERT_CHAR:
  1310.         PUSH    SI
  1311.         PUSH    AX        ;Save the new character
  1312.         MOV    AX,1
  1313.         CALL    OPEN_SPACE    ;Make room for it
  1314.         POP    AX        ;Get back the new character
  1315.         POP    DI
  1316.         JC    FILE_FULL
  1317.         STOSB            ;Insert character in file buffer
  1318. ADVANCE:
  1319.         OR    DIRTY_BITS,4    ;Current line is dirty
  1320.         PUSH    UNDO_LENGTH
  1321.         CALL    RIGHT        ;Move cursor to next letter
  1322.         POP    UNDO_LENGTH
  1323. FILE_FULL:
  1324.         RET
  1325. NEW_LINE:
  1326.         PUSH    SI
  1327.         MOV    AX,2
  1328.         CALL    OPEN_SPACE    ;Make space for CR and LF
  1329.         POP    DI        ;Get back old cursor location
  1330.         JC    FILE_FULL
  1331.         MOV    AX,LF*256+CR
  1332.         STOSW            ;Store the CR and LF
  1333.         CALL    DISPLAY_BOTTOM    ;Repaint bottom of the screen
  1334.         CALL    HOME        ;Cursor to start of line
  1335.         JMP    DOWN        ;Move down to the new line
  1336. INSERT_KEY    ENDP
  1337.  
  1338. ;-----------------------------------------------------------------------
  1339. ; This subroutine inserts spaces into the file buffer.  On entry AX
  1340. ; contains the number of spaces to be inserted.  On return, CF=1 if
  1341. ; there was not enough space in the file buffer.
  1342. ;-----------------------------------------------------------------------
  1343. OPEN_SPACE    PROC    NEAR
  1344.         MOV    CX,LAST_CHAR    ;Last character in the file
  1345.         MOV    SI,CX
  1346.         MOV    DI,CX
  1347.         ADD    DI,AX        ;Offset for new end of file
  1348.         JC    NO_ROOM        ;If no more room, return error
  1349.         MOV    LAST_CHAR,DI    ;Save offset of end of file
  1350.         SUB    CX,CURSOR    ;Number of characters to shift
  1351.         DEC    DI
  1352.         DEC    SI
  1353.         STD            ;String moves goes forward
  1354.         REP    MOVSB        ;Shift the file upward
  1355.         CLD
  1356.         CLC
  1357. NO_ROOM:
  1358.         RET
  1359. OPEN_SPACE    ENDP
  1360.  
  1361. ;-----------------------------------------------------------------------
  1362. ; This subroutine adjusts the cursor position ahead to the saved cursor
  1363. ; column.  On entry DH has the cursor row.
  1364. ;-----------------------------------------------------------------------
  1365. SHIFT_RIGHT    PROC    NEAR
  1366.         MOV    CL,SAVE_COLUMN    ;Keep the saved cursor offset
  1367.         XOR    CH,CH
  1368.         MOV    BP,CX        ;Keep the saved cursor position
  1369.         ADD    CL,LEFT_MARGIN    ;Shift into visable window also
  1370.         ADC    CH,0
  1371.         XOR    DL,DL
  1372.         MOV    CUR_POSN,DX    ;Get cursor row/column
  1373.         JCXZ    NO_CHANGE
  1374. RIGHT_AGAIN:
  1375.         PUSH    CX
  1376.         CMP    BYTE PTR [SI],CR;At end of line?
  1377.         JE    DONT_MOVE    ;If at end, stop moving
  1378.         CALL    RIGHT        ;Move right one character
  1379. DONT_MOVE:
  1380.         POP    CX
  1381.  
  1382.         MOV    AL,SAVE_COLUMN
  1383.         XOR    AH,AH
  1384.         CMP    AX,CX        ;Is cursor still in margin?
  1385.         JL    IN_MARGIN    ;If yes, keep moving
  1386.  
  1387.         MOV    DX,CUR_POSN    ;Get cursor column again
  1388.         XOR    DH,DH
  1389.         CMP    DX,BP        ;At saved cursor position?
  1390.         JE    RIGHT_DONE    ;If yes, were done
  1391.         JA    RIGHT_TOO_FAR    ;Did we go too far?
  1392. IN_MARGIN:
  1393.         LOOP    RIGHT_AGAIN
  1394. RIGHT_DONE:
  1395.         MOV    CX,BP
  1396.         MOV    SAVE_COLUMN,CL    ;Get back saved cursor position
  1397. NO_CHANGE:
  1398.         RET
  1399. RIGHT_TOO_FAR:
  1400.         CALL    LEFT        ;Move back left one place
  1401.         MOV    CX,BP
  1402.         MOV    SAVE_COLUMN,CL    ;Get back saved cursor position
  1403.         RET
  1404. SHIFT_RIGHT    ENDP
  1405.  
  1406. ;-----------------------------------------------------------------------
  1407. ; This subroutine skips past the CR and LF at SI.  SI returns new offset
  1408. ;-----------------------------------------------------------------------
  1409. SKIP_CR_LF    PROC    NEAR
  1410.         CMP    SI,LAST_CHAR    ;At last char in the file?
  1411.         JAE    NO_SKIP        ;If yes, dont skip anything
  1412.         CMP    BYTE PTR [SI],CR;Is first character a CR?
  1413.         JNE    NO_SKIP
  1414.         INC    SI        ;Look at next character
  1415.         CMP    SI,LAST_CHAR    ;Is it at the end of file?
  1416.         JAE    NO_SKIP        ;If yes, dont skip anymore
  1417.         CMP    BYTE PTR [SI],LF;Is next character a line feed?
  1418.         JNE    NO_SKIP        ;Skip any line feeds also
  1419.         INC    SI
  1420. NO_SKIP:
  1421.         RET
  1422. SKIP_CR_LF    ENDP
  1423.  
  1424. ;-----------------------------------------------------------------------
  1425. ; This subroutine finds the beginning of the previous line.
  1426. ;-----------------------------------------------------------------------
  1427. FIND_PREVIOUS    PROC    NEAR
  1428.         PUSH    CURSOR        ;Save the cursor location
  1429.         CALL    FIND_CR        ;Find start of this line
  1430.         MOV    CURSOR,SI    ;Save the new cursor
  1431.         CALL    FIND_START    ;Find the start of this line
  1432.         POP    CURSOR        ;Get back starting cursor
  1433.         RET
  1434. FIND_PREVIOUS    ENDP
  1435.  
  1436. ;-----------------------------------------------------------------------
  1437. ; This searches for the previous carriage return.  Search starts at SI.
  1438. ;-----------------------------------------------------------------------
  1439. FIND_CR        PROC    NEAR
  1440.         PUSH    CX
  1441.         MOV    AL,LF        ;Look for a carriage return
  1442.         MOV    DI,SI
  1443.         MOV    CX,SI
  1444.         JCXZ    AT_BEGINNING
  1445.         DEC    DI
  1446.         STD            ;Search backwards
  1447. LF_PREV:
  1448.         REPNE    SCASB        ;Scan for the character
  1449.         JCXZ    LF_END
  1450.         CMP    BYTE PTR [DI],CR
  1451.         JNE    LF_PREV
  1452.         DEC    DI
  1453. LF_END:
  1454.         CLD            ;Restore direction flag
  1455.         INC    DI
  1456.         MOV    SI,DI
  1457. AT_BEGINNING:
  1458.         POP    CX
  1459.         RET
  1460. FIND_CR        ENDP
  1461.  
  1462. ;-----------------------------------------------------------------------
  1463. ; This subroutine computes the location of the start of current line.
  1464. ; Returns SI pointing to the first character of the current line.
  1465. ;-----------------------------------------------------------------------
  1466. FIND_START    PROC    NEAR
  1467.         MOV    SI,CURSOR    ;Get the current cursor
  1468.         OR    SI,SI        ;At start of the file?
  1469.         JZ    AT_START    ;If yes, were done
  1470.         CALL    FIND_CR        ;Find the 
  1471.         CALL    SKIP_CR_LF
  1472. AT_START:
  1473.         RET
  1474. FIND_START    ENDP
  1475.  
  1476. ;-----------------------------------------------------------------------
  1477. ; This finds the offset of the start of the next line.  The search is 
  1478. ; started at location ES:SI.  On return CF=1 of no CR was found.
  1479. ;-----------------------------------------------------------------------
  1480. FIND_NEXT    PROC    NEAR
  1481.         PUSH    CX
  1482.         CALL    FIND_EOL    ;Find the end of this line
  1483.         JC    AT_NEXT        ;If at end of file, return
  1484.         CALL    SKIP_CR_LF    ;Skip past CR and LF
  1485.         CLC            ;Indicate end of line found
  1486. AT_NEXT:                  
  1487.         POP    CX
  1488.         RET
  1489. FIND_NEXT    ENDP
  1490.  
  1491. ;-----------------------------------------------------------------------
  1492. ; This searches for the next carriage return in the file.  The search
  1493. ; starts at the offset in register SI.
  1494. ;-----------------------------------------------------------------------
  1495. FIND_EOL    PROC    NEAR
  1496.         MOV    AL,CR        ;Look for a carriage return
  1497. CR_SCAN:
  1498.         MOV    CX,LAST_CHAR    ;Last letter in the file
  1499.         SUB    CX,SI        ;Count for the search
  1500.         MOV    DI,SI
  1501.         JCXZ    AT_END        ;If nothing to search, return
  1502.         REPNE    SCASB        ;Scan for the character
  1503.         MOV    SI,DI        ;Return the location of the CR
  1504.         JCXZ    AT_END        ;If not found, return
  1505.         CMP    BYTE PTR [SI],LF
  1506.         JNE    CR_SCAN
  1507.         DEC    SI
  1508.         CLC            ;Indicate the CR was found
  1509.         RET
  1510. AT_END:
  1511.         STC            ;Indicate CR was not found
  1512.         RET
  1513. FIND_EOL    ENDP
  1514.  
  1515. ;-----------------------------------------------------------------------
  1516. ; This subroutine positions the screen with the cursor at the row
  1517. ; selected in register DH.  On entry, SI holds the cursor offset.
  1518. ;-----------------------------------------------------------------------
  1519. LOCATE        PROC    NEAR
  1520.         MOV    CL,DH
  1521.         XOR    CH,CH
  1522.         MOV    CURSOR,SI
  1523.         XOR    DX,DX        ;Start at top of the screen
  1524.         OR    SI,SI        ;At start of buffer?
  1525.         JZ    LOCATE_FIRST
  1526.  
  1527.         CALL    FIND_START    ;Get start of this row
  1528.         XOR    DX,DX        ;Start at top of the screen
  1529.         OR    SI,SI        ;Is cursor at start of file?
  1530.         JZ    LOCATE_FIRST
  1531.         JCXZ    LOCATE_FIRST    ;If locating to top row were done
  1532. FIND_TOP:
  1533.         PUSH    SI
  1534.         PUSH    CX
  1535.         CALL    FIND_CR        ;Find previous row
  1536.         POP    CX
  1537.         POP    AX
  1538.         CMP    BYTE PTR [SI],CR
  1539.         JNE    LOCATE_FIRST
  1540.         CMP    BYTE PTR [SI+1],LF
  1541.         JNE    LOCATE_FIRST
  1542.         CMP    SI,AX        ;Did it change?
  1543.         JE    LOCATE_DONE    ;If not, quit moving
  1544.         INC    DH        ;Cursor moves to next row
  1545.         LOOP    FIND_TOP
  1546.  
  1547. LOCATE_DONE:
  1548.         PUSH    CURSOR
  1549.         MOV    CURSOR,SI
  1550.         CALL    FIND_START    ;Find start of top of screen
  1551.         POP    CURSOR
  1552. LOCATE_FIRST:
  1553.         MOV    TOP_OF_SCREEN,SI
  1554.         MOV    CUR_POSN,DX
  1555.         CALL    CURSOR_COL
  1556.         MOV    SAVE_COLUMN,DL
  1557.         RET
  1558. LOCATE        ENDP
  1559.  
  1560. ;-----------------------------------------------------------------------
  1561. ; This subroutine computes the correct column for the cursor.  No
  1562. ; inputs.  On exit, CUR_POSN is set and DX has the row/column.
  1563. ;-----------------------------------------------------------------------
  1564. CURSOR_COL    PROC    NEAR
  1565.         MOV    SI,CURSOR    ;Get cursor offset
  1566.         CALL    FIND_START    ;Find start of this line
  1567.         MOV    CX,CURSOR
  1568.         SUB    CX,SI
  1569.         MOV    DX,CUR_POSN    ;Get current row
  1570.         XOR    DL,DL        ;Start at column zero
  1571.         MOV    MARGIN_COUNT,DL    ;Count past the left margin
  1572.         JCXZ    COL_DONE
  1573. CURSOR_LOOP:
  1574.         LODSB            ;Get the next character
  1575.         CMP    AL,CR        ;Is it the end of line?
  1576.         JNE    NOT_EOL
  1577.         CMP    BYTE PTR [SI],LF
  1578.         JE    COL_DONE    ;If end, were done
  1579. NOT_EOL:
  1580.         CMP    AL,TAB        ;Is it a tab?
  1581.         JNE    NOT_A_TAB
  1582.  
  1583.         MOV    BL,MARGIN_COUNT
  1584.         OR    BL,00000111B
  1585.         MOV    MARGIN_COUNT,BL
  1586.         CMP    BL,LEFT_MARGIN    ;Inside visible window yet?
  1587.         JB    NOT_A_TAB    ;If not, don't advance cursor
  1588.         OR    DL,00000111B    ;Move to multiple of eight
  1589. NOT_A_TAB:
  1590.         MOV    BL,MARGIN_COUNT
  1591.         INC    BL
  1592.         MOV    MARGIN_COUNT,BL
  1593.         CMP    BL,LEFT_MARGIN
  1594.         JBE    OUT_OF_WINDOW
  1595.         INC    DL        ;Were at next column now
  1596. OUT_OF_WINDOW:
  1597.         LOOP    CURSOR_LOOP
  1598. COL_DONE:
  1599.         CMP    DL,COLUMNSB    ;Past end of display?
  1600.         JB    COLUMN_OK    ;If not, were OK?
  1601.         MOV    DL,COLUMNSB
  1602.         DEC    DL        ;Leave cursor at last column
  1603. COLUMN_OK:
  1604.         MOV    CUR_POSN,DX    ;Store the row/column
  1605.         RET
  1606. CURSOR_COL    ENDP
  1607.  
  1608. ;-----------------------------------------------------------------------
  1609. ; This displays the string at CS:SI at the location in DX.  The 
  1610. ; remainder of the row is erased.  Cursor is put at the end of the line.
  1611. ;-----------------------------------------------------------------------
  1612. TTY_STRING    PROC    NEAR
  1613.         ASSUME    DS:CSEG
  1614.         PUSH    DX
  1615.         CALL    POSITION    ;Compute offset into video
  1616.         POP    DX
  1617. TTY_LOOP:
  1618.         LODSB
  1619.         OR    AL,AL        ;At end of string yet?
  1620.         JZ    TTY_DONE
  1621.         INC    DL
  1622.         PUSH    DX
  1623.         CALL    WRITE_INVERSE    ;Write in inverse video
  1624.         POP    DX
  1625.         JMP    TTY_LOOP
  1626. TTY_DONE:
  1627.         CALL    SET_CURSOR    ;Move cursor to end of string
  1628.         JMP    ERASE_EOL    ;Erase the rest of line
  1629. TTY_STRING    ENDP
  1630.  
  1631. ;-----------------------------------------------------------------------
  1632. ; This copies the input filename to CS:DI and changes the extension
  1633. ;-----------------------------------------------------------------------
  1634. CHG_EXTENSION    PROC    NEAR
  1635.         ASSUME    DS:CSEG, ES:CSEG
  1636.  
  1637.         PUSH    SI
  1638.         MOV    SI,NAME_POINTER
  1639. CHG_LOOP:
  1640.         LODSB        
  1641.         CMP    AL,"."        ;Look for the extension
  1642.         JE    FOUND_DOT
  1643.         OR    AL,AL
  1644.         JZ    FOUND_DOT
  1645.         STOSB            ;Copy a character
  1646.         JMP    CHG_LOOP
  1647. FOUND_DOT:
  1648.         MOV    CX,5        ;Five chars in extension
  1649.         POP    SI
  1650.         REP    MOVSB        ;Move new extension in
  1651.         RET
  1652. CHG_EXTENSION    ENDP
  1653.  
  1654. ;-----------------------------------------------------------------------
  1655. ; This is the control break handler.  It ignores the break.
  1656. ;-----------------------------------------------------------------------
  1657. NEWINT23    PROC    FAR
  1658.         ASSUME    DS:NOTHING, ES:NOTHING
  1659.         MOV    CS:DIRTY_BITS,1
  1660.         CLC            ;Tell DOS to ignore break
  1661.         IRET
  1662. NEWINT23    ENDP
  1663.  
  1664. ;-----------------------------------------------------------------------
  1665. ; This is the severe error handler.  It homes the cursor before 
  1666. ; processing the error.
  1667. ;-----------------------------------------------------------------------
  1668. NEWINT24    PROC    FAR
  1669.         ASSUME    DS:NOTHING, ES:NOTHING
  1670.         PUSHF
  1671.         PUSH    AX
  1672.         PUSH    BX
  1673.         PUSH    DX
  1674.         MOV    CS:DIRTY_BITS,1
  1675.         XOR    DX,DX
  1676.         CALL    SET_CURSOR    ;Put cursor at home
  1677.         POP    DX
  1678.         POP    BX
  1679.         POP    AX
  1680.         POPF
  1681.         JMP    CS:OLDINT24
  1682. NEWINT24    ENDP
  1683. ;-----------------------------------------------------------------------
  1684. EVEN
  1685. NAME_DOT_$$$    EQU    $
  1686. NAME_DOT_BAK    EQU    $ + 80H
  1687. UNDO_BUFFER    EQU    $ + 100H
  1688. LINE_BUFFER    EQU    $ + 200H
  1689. NEW_STACK    EQU    $ + 500H
  1690. CSEG        ENDS
  1691. ;-----------------------------------------------------------------------
  1692. FILE_SEG    SEGMENT
  1693. FILE_SEG    ENDS
  1694. END        START
  1695.